/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.persistence.hibernate.core;

import com.blandware.atleap.common.util.PartialCollection;
import com.blandware.atleap.common.util.QueryInfo;
import com.blandware.atleap.model.core.ActionPage;
import com.blandware.atleap.model.core.ContentField;
import com.blandware.atleap.model.core.ContentFieldValue;
import com.blandware.atleap.model.core.ContentLocale;
import com.blandware.atleap.persistence.core.ActionPageDAO;
import com.blandware.atleap.persistence.exception.DeleteException;

import java.util.*;

/**
 * <p>Hibernate implementation of ActionPageDAO</p>
 * <p><a href="ActionPageDAOHibernate.java.html"><i>View Source</i></a></p>
 *
 * @author Sergey Zubtsovskiy <a href="mailto:sergey.zubtsovskiy@blandware.com">&lt;sergey.zubtsovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.36 $ $Date: 2008/06/23 13:24:53 $
 */

public class ActionPageDAOHibernate extends PageDAOHibernate implements ActionPageDAO {

	/**
	 * Creates new instance of ActionPageDAOHibernate
	 */
	public ActionPageDAOHibernate() {
	}

	// ~ CRUD Methods ================================================================

	/**
	 * @see com.blandware.atleap.persistence.core.ActionPageDAO#createActionPage(com.blandware.atleap.model.core.ActionPage)
	 */
	public Long createActionPage(ActionPage actionPage) {
		actionPage.setUsageCounter(new Integer(0));
        actionPage.setLastUpdatedDatetime(new Date());
        Long actionPageId = (Long) getHibernateTemplate().save(actionPage);

		// title
		ContentField fTitle = new ContentField();
		fTitle.setIdentifier("title");
		fTitle.setType(ContentField.LINE_TYPE);
		fTitle.setInternal(Boolean.TRUE);
		actionPage.addContentField(fTitle);
		getHibernateTemplate().save(fTitle);

		// description
		ContentField fDescription = new ContentField();
		fDescription.setIdentifier("description");
		fDescription.setType(ContentField.LINE_TYPE);
		fDescription.setInternal(Boolean.TRUE);
		actionPage.addContentField(fDescription);
		getHibernateTemplate().save(fDescription);

		// keywords
		ContentField fKeywords = new ContentField();
		fKeywords.setIdentifier("keywords");
		fKeywords.setType(ContentField.LINE_TYPE);
		fKeywords.setInternal(Boolean.TRUE);
		actionPage.addContentField(fKeywords);
		getHibernateTemplate().save(fKeywords);

        // Fill in content field values for title, keywords and description
        // fields for every content locale
		List contentLocales = executeFind("from ContentLocale l", true, "query.listContentLocales");
		for ( int i = 0; i < contentLocales.size(); i++ ) {
			ContentLocale contentLocale = (ContentLocale) contentLocales.get(i);
			String localeIdentifier = contentLocale.getIdentifier();

            // values for title, description and keywords in that locale
			String valueTitle = (String) actionPage.getTitle().get(localeIdentifier);
			String valueDescription = (String) actionPage.getDescription().get(localeIdentifier);
			String valueKeywords = (String) actionPage.getKeywords().get(localeIdentifier);

			//title
			ContentFieldValue fvTitle = new ContentFieldValue();
			fvTitle.setContentLocale(contentLocale);
			if ( valueTitle != null ) {
				fvTitle.setSimpleValue(valueTitle);
			} else {
				fvTitle.setSimpleValue("");
			}
			fvTitle.setLastUpdatedDatetime(new Date());
			fTitle.addContentFieldValue(fvTitle);
			getHibernateTemplate().save(fvTitle);

			//description
			ContentFieldValue fvDescription = new ContentFieldValue();
			fvDescription.setContentLocale(contentLocale);
			if ( valueDescription != null ) {
				fvDescription.setSimpleValue(valueDescription);
			} else {
				fvDescription.setSimpleValue("");
			}
			fvDescription.setLastUpdatedDatetime(new Date());
			fDescription.addContentFieldValue(fvDescription);
			getHibernateTemplate().save(fvDescription);

			//keywords
			ContentFieldValue fvKeywords = new ContentFieldValue();
			fvKeywords.setContentLocale(contentLocale);
			if ( valueKeywords != null ) {
				fvKeywords.setSimpleValue(valueKeywords);
			} else {
				fvKeywords.setSimpleValue("");
			}
			fvKeywords.setLastUpdatedDatetime(new Date());
			fKeywords.addContentFieldValue(fvKeywords);
			getHibernateTemplate().save(fvKeywords);
		}

		return actionPageId;

	}

	/**
	 * @see com.blandware.atleap.persistence.core.ActionPageDAO#retrieveActionPage(java.lang.Long)
	 */
	public ActionPage retrieveActionPage(Long actionPageId) {
		String hql = new StringBuffer("select distinct page, title.contentLocale.identifier, title.simpleValue, description.simpleValue, keywords.simpleValue ")
		        .append("from ActionPage as page left outer join ")
		        .append("page.contentFields titleField left outer join titleField.contentFieldValues as title left outer join ")
		        .append("page.contentFields descriptionField left outer join descriptionField.contentFieldValues as description ")
		        .append("left outer join page.contentFields keywordsField left outer join keywordsField.contentFieldValues as keywords ")
		        .append("where ")
		        .append("((title.contentLocale = description.contentLocale and title.contentLocale = keywords.contentLocale) or (title is null and description is null and keywords is null)) ")
		        .append("and titleField.identifier = 'title' ")
		        .append("and descriptionField.identifier = 'description' and keywordsField.identifier = 'keywords' and page.id = ?")
		        .toString();

        // Get a list of quintuples (page, locale identifier, title value,
        // description value, keywords value)
		List list = executeFind(hql, new Object[]{actionPageId});
        // Assign those values to corresponding pages -- get list of pages with
        // title, description and keywords correctly assigned
		List result = setLocalizableFields(list);
		if ( result == null || result.size() <= 0 ) {
			return null;
		} else {
			return (ActionPage) result.get(0);
		}
	}

	/**
	 * @see com.blandware.atleap.persistence.core.ActionPageDAO#updateActionPage(com.blandware.atleap.model.core.ActionPage)
	 */
	public void updateActionPage(ActionPage actionPage) {
		getHibernateTemplate().update(actionPage);
        // Update internal fields (title, description and keywords) of this page
		for ( int i = 0; i < actionPage.getContentFields().size(); i++ ) {
			ContentField contentField = (ContentField) actionPage.getContentFields().get(i);
			Map values;
			if ( "title".equalsIgnoreCase(contentField.getIdentifier()) ) {
				values = actionPage.getTitle();
			} else if ( "description".equalsIgnoreCase(contentField.getIdentifier()) ) {
				values = actionPage.getDescription();
			} else if ( "keywords".equalsIgnoreCase(contentField.getIdentifier()) ) {
				values = actionPage.getKeywords();
			} else {
                continue;
            }
			for ( int j = 0; j < contentField.getContentFieldValues().size(); j++ ) {
				ContentFieldValue contentFieldValue = (ContentFieldValue) contentField.getContentFieldValues().get(j);
				String localeIdentifier = contentFieldValue.getContentLocale().getIdentifier();
				String value = (String) values.get(localeIdentifier);
				if ( value != null ) {
					contentFieldValue.setSimpleValue(value);
				} else {
					contentFieldValue.setSimpleValue("");
				}
				contentFieldValue.setLastUpdatedDatetime(new Date());
				contentFieldValue.getContentField().updateContentFieldValue(contentFieldValue);
				getHibernateTemplate().update(contentFieldValue);
			}
		}
	}

	/**
	 * @see com.blandware.atleap.persistence.core.ActionPageDAO#deleteActionPage(com.blandware.atleap.model.core.ActionPage)
	 */
	public void deleteActionPage(ActionPage actionPage) throws DeleteException {
        removeAssociations(actionPage);

		getHibernateTemplate().delete(actionPage);
	}

	// ~ Additional methods ================================================================

	/**
	 * @see com.blandware.atleap.persistence.core.ActionPageDAO#listActionPages(com.blandware.atleap.common.util.QueryInfo)
	 */
	public PartialCollection listActionPages(QueryInfo queryInfo) {
		String whereClause = "";
		String orderByClause = "";
		if ( queryInfo != null ) {
			whereClause = queryInfo.getWhereClause();
			orderByClause = queryInfo.getOrderByClause();
			if ( whereClause == null || whereClause.length() == 0 ) {
				whereClause = "";
			}
			if ( orderByClause != null && orderByClause.length() != 0 ) {
				orderByClause = " order by " + orderByClause;
			} else {
				orderByClause = "";
			}
		}

		List list;
		Integer total = null;

		String localeIdentifier = null;
		if ( queryInfo != null ) {
			if ( queryInfo.getQueryParameters() != null ) {
				localeIdentifier = (String) queryInfo.getQueryParameters().get("localeIdentifier");
			}
		}

		boolean localeIdentifierPresent = localeIdentifier != null && localeIdentifier.length() > 0;

		String hqlPart;
		ArrayList args = new ArrayList();
		if ( localeIdentifierPresent ) {
			args.add(localeIdentifier);
			hqlPart = new StringBuffer("from ActionPage as page ")
			        .append("left outer join page.contentFields as titleField ")
			        .append("left outer join page.contentFields as descriptionField ")
			        .append("left outer join page.contentFields as keywordsField ")
			        .append("left outer join titleField.contentFieldValues as title ")
			        .append("left outer join descriptionField.contentFieldValues as description ")
			        .append("left outer join keywordsField.contentFieldValues as keywords ")
			        .append("where ")
			        .append("titleField.identifier = 'title' and descriptionField.identifier = 'description' and keywordsField.identifier = 'keywords' ")
			        .append("and title.contentLocale = description.contentLocale and title.contentLocale = keywords.contentLocale ")
			        .append("and title.contentLocale.identifier = ? ")
			        .toString();
			if ( whereClause.length() > 0 ) {
				hqlPart += "and " + whereClause;
			}
		} else {
			hqlPart = "from ActionPage page ";
			if ( whereClause.length() > 0 ) {
				hqlPart += "where " + whereClause;
			}
		}

		if ( queryInfo != null && (queryInfo.getLimit() != null || queryInfo.getOffset() != null) ) {
			// query count
			String hqlForTotal = "select count(distinct page.id) " + hqlPart;
			total = findUniqueIntegerResult(hqlForTotal, args.toArray());
			if ( total == null ) {
				total = new Integer(0);
			}
		}

        // If we don't have any info about the total number of results yet or
        // we know that there's something that will be found, then fetch data
		if ( total == null || total.intValue() > 0 ) {
			String hql;
			if ( localeIdentifierPresent ) {
				hql = "select distinct page, title.simpleValue, description.simpleValue, keywords.simpleValue " + hqlPart + orderByClause;
			} else {
				hql = "select page " + hqlPart + orderByClause;
			}
			list = executeFind(hql, queryInfo, args.toArray());
			if ( total == null ) {
				total = new Integer(list.size());
			}
			if ( localeIdentifierPresent ) {
                // Replace each tuple in list with a page with title, description
                // and keywords assigned
				for ( ListIterator i = list.listIterator(); i.hasNext(); ) {
					Object[] objects = (Object[]) i.next();
					ActionPage actionPage = (ActionPage) objects[0];
					actionPage.getTitle().put(localeIdentifier, objects[1]);
					actionPage.getDescription().put(localeIdentifier, objects[2]);
					actionPage.getKeywords().put(localeIdentifier, objects[3]);
					i.set(actionPage);
				}
			}
		} else {
			list = new ArrayList();
		}

		return new PartialCollection(list, total);

	}
	// ~ Finders ================================================================

	/**
	 * @see com.blandware.atleap.persistence.core.ActionPageDAO#findActionPageByUri(java.lang.String)
	 */
	public ActionPage findActionPageByUri(String actionPageUri) {
		return (ActionPage) findUniqueResult("from ActionPage page where page.uri = ?", new Object[]{actionPageUri});
	}

	// ~ Helper methods

}
